#include <string>
#include <vector>
#include <memory>
#include <fstream>
#include <sstream>
#include <algorithm>
typedef std::vector<std::string> VELE;
typedef std::vector<VELE> VMAP;

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
T str2any(const std::string& s) {
    T d;
    std::stringstream ss(s);
    ss >> d;
    return d;
}

int hexStr2int(const std::string& s) {
    int ch = -1;
    std::istringstream iss(s);
    iss >> std::hex;
    iss >> ch;
    return ch;
}

bool isHexStr(const std::string& s) {
    auto pos = s.find("0x");
    return pos != std::string::npos;
}

bool isIntStr(const std::string& s) {
    auto isInt = [](char ch) -> bool {
        if (ch >= '0' && ch <= '9') return true;
        return false;
    };

    for (int i = 0; i < s.length(); ++i) {
        if (!isInt(s.at(i))) return false;
    }
    return true;
}

std::string intStr2HexStr(const std::string& s) {
    int len = s.length() + 3;
    char *buf = new char[len];
    memset(buf, 0, len);
    sprintf(buf, "%x", str2any<int>(s));
    std::string ret = buf;
    delete buf;

    for (int i = 4 - ret.length(); i > 0; --i) {
        ret = "0" + ret;
    }
    ret = "0x" + ret;

    return std::move(ret);
}

std::string readFile(const std::string& file) {
    std::ifstream t(file);  
    std::stringstream buffer;  
    buffer << t.rdbuf();  
    t.close();
    return buffer.str();
}

void writeFile(const std::string& file, const std::string& data) {
    std::ofstream t;
    t.open(file, std::ios::trunc);
    t << data;
    t.close();
}

std::shared_ptr<VMAP> parserData(const std::string& data) {
    static auto getText = [](const std::string& xml) -> auto {
        std::string ret;

        bool bstop = false;
        for (int i = 0; i < xml.length(); ++i) {
            if (xml[i] == '<') bstop = true;
            else if (xml[i] == '>') bstop = false;
            else if (!bstop) {
                if (xml[i] == '\r' || xml[i] == '\n' || xml[i] == '\r\n') {
                    continue;
                }
                ret += xml[i];
            }
        }

        return std::move(ret);
    };

    static auto getTd = [](const std::string& xml, int pos, std::string& d)-> int {
        auto bp = xml.find("<td ", pos);
        if (bp == std::string::npos) bp = xml.find("<td>", pos);
        auto ep = xml.find("</td>", pos);
        if (bp == std::string::npos) return -1;
        if (ep == std::string::npos) return -1;

        auto td = xml.substr(bp, ep - bp + 5);

        auto t = getText(td);
        if (isHexStr(t)) d = std::move(t);
        else if (isIntStr(t)) d = intStr2HexStr(t);
        else d = std::move(t);

        return ep + 5;
    };
    static auto getTr = [&data](int pos, VELE& v)-> int {
        auto bp = data.find("<tr ", pos);
        if (bp == std::string::npos) bp = data.find("<tr>", pos);
        auto ep = data.find("</tr>", pos);
        if (bp == std::string::npos) return -1;
        if (ep == std::string::npos) return -1;

        auto tr = data.substr(bp , ep + 5 - bp);

        for (int pos = 0; pos < tr.length(); ) {
            std::string d;
            pos = getTd(tr, pos, d);
            if (pos < 0) break;
            v.push_back(d);
        }
        return ep + 5;
    };

    auto map = std::make_shared<VMAP>();
    for (int pos = 0; pos < data.length(); ) {
        VELE v;
        pos = getTr(pos, v);
        if (pos < 0) break;
        map->push_back(v);
    }

    return map;
}

std::string mergeData(std::shared_ptr<VMAP>& data) {
    std::string info;
    for (auto it = data->begin(); it != data->end(); ++it) {
        info += "['";
        info += (*it).at(0) + "', '";
        info += (*it).at(1) + "', '";
        info += (*it).at(2);
        info += "'],\n";
    }
    return std::move(info);
}

void sort(std::shared_ptr<VMAP>& data) {
    std::sort(data->begin(), data->end(), [](const VELE& v1, const VELE& v2) -> bool {
        auto d1 = hexStr2int(v1.at(1));
        auto d2 = hexStr2int(v2.at(1));
        return d1 < d2;
    });
}

// add src to dst.
void addToVmap(std::shared_ptr<VMAP>& src, std::shared_ptr<VMAP>& dst) {
    auto had = [&dst](const VELE& v) -> bool {
        auto d2 = hexStr2int(v.at(1));
        for (auto it = dst->begin(); it != dst->end(); ++it) {
            auto d1 = hexStr2int((*it).at(1));
            if (d1 == d2) return true;
        }
        return false;
    };

    for (auto it = src->begin(); it != src->end(); ++it) {
        if (!had(*it)) dst->push_back(*it);
    }
}

int main(int argc, char** argv)
{
    if (argc <= 1) {
        cout << "<> run aaa.html" << endl;
    } else {
        auto map = std::make_shared<VMAP>();
        std::string outfile = "out.js";
        for (int i = 1; i < argc; ++i) {
            auto data = parserData(readFile(argv[i]));
            if (!data) {
                cout << "Error param " << argv[i] << endl;
                return 0;
            }
            addToVmap(data, map);
        }
        sort(map);
        writeFile(outfile, mergeData(map));
        cout << "Done! to " << outfile << endl;
    }

    return 0;
}